package com.trg.flex.frm
{
	import com.trg.flex.messages.Message;
	
	import flash.display.DisplayObjectContainer;
	import flash.events.Event;
	import flash.events.EventPhase;
	import flash.events.KeyboardEvent;
	import flash.events.MouseEvent;
	import flash.ui.Keyboard;
	
	import mx.binding.utils.ChangeWatcher;
	import mx.containers.ControlBar;
	import mx.containers.TitleWindow;
	import mx.controls.Button;
	import mx.controls.LinkButton;
	import mx.events.FlexEvent;
	import mx.managers.PopUpManager;

	[DefaultProperty("form")]
	public class FormDialog extends TitleWindow
	{
		private var _form:FormContainer;
		private var displayParent:DisplayObjectContainer;
		private var cancelButton:Button;
		
		private var _controlBar:ControlBar = new ControlBar();
		private var commitAndNew:Button = new Button();
		private var commitAndClose:Button = new Button();
		private var commit:Button = new Button();
		private var clear:Button = new Button();
		private var reset:Button = new Button();
		private var close:LinkButton = new LinkButton();
		
		public function FormDialog() {
			super();
			this.styleName="popup";
			this.addEventListener(FlexEvent.ADD, onAdd);
			buildDialog();
			defaultButton = commitAndClose;
			cancelButton = close;
		}
		
		private function buildDialog():void {
			showCommit = false;
			showClear = false;
			commitAndNewLabel = "Save and Add Another";
			commitAndCloseLabel = "Save";
			commitLabel = "Apply";
			clearLabel = "Clear";
			resetLabel = "Reset";
			closeLabel = "Cancel";
			
			_controlBar.setStyle("horizontalAlign", "right");
			_controlBar.addChild(commitAndNew);
			_controlBar.addChild(commitAndClose);
			_controlBar.addChild(commit);
			_controlBar.addChild(clear);
			_controlBar.addChild(reset);
			_controlBar.addChild(close);
			this.addChild(_controlBar);
			
			commitAndNew.addEventListener(MouseEvent.CLICK, clickHandler);
			commitAndClose.addEventListener(MouseEvent.CLICK, clickHandler);
			commit.addEventListener(MouseEvent.CLICK, clickHandler);
			clear.addEventListener(MouseEvent.CLICK, clickHandler);
			reset.addEventListener(MouseEvent.CLICK, clickHandler);
			close.addEventListener(MouseEvent.CLICK, clickHandler);
			
			this.addEventListener(KeyboardEvent.KEY_DOWN, keyListener, true);
			this.addEventListener(KeyboardEvent.KEY_DOWN, keyListener);
		}
		
		private function onAdd(event:FlexEvent):void {
			var self:FormDialog = event.target as FormDialog;
			if (this.displayParent == null) this.displayParent = this.parent;
			this.parent.removeChild(this);
			this.visible = true;
			this.includeInLayout = true;
			this.removeEventListener(FlexEvent.ADD, onAdd);
		}
		
		private function clickHandler(event:Event):void {
			buttonClicked = true;
			trace("click");
			switch (event.target) {
				case commitAndNew:
					if (_form != null) {
						todoOnComplete = TODO_NEW;
						_form.commit();
					}
					break;
				case commitAndClose:
					if (_form != null) {
						todoOnComplete = TODO_CLOSE;
						_form.commit();
					}
					break;
				case commit:
					if (_form != null) {
						todoOnComplete = TODO_NOTHING;
						_form.commit();
					}
					break;
				case clear:
					if (_form != null) {
						_form.clear();
						_form.resetFocus();
					}
					break;
				case reset:
					if (_form != null) {
						_form.reset();
						_form.resetFocus();
					}
					break;
				case close:
					hide();
				break;
			}
		}
		
		private var buttonClicked:Boolean = false;
		private function keyListener(event:KeyboardEvent):void {
			if (event.eventPhase == EventPhase.CAPTURING_PHASE) {
				buttonClicked = false;
			} else if (buttonClicked == false) {
				if (event.keyCode == Keyboard.ENTER && defaultButton != null) {
					var e:MouseEvent = new MouseEvent(MouseEvent.CLICK);
					defaultButton.dispatchEvent(e);
				} else if (event.keyCode == Keyboard.ESCAPE && cancelButton != null) {
					var e2:MouseEvent = new MouseEvent(MouseEvent.CLICK);
					cancelButton.dispatchEvent(e2);
				}
			}
		}
		
		private static const TODO_NOTHING:int = 0, TODO_NEW:int = 1, TODO_CLOSE:int = 2;
		private var todoOnComplete:int;
		
		private function commitCompleteHandler(event:FormEvent):void {
			if (todoOnComplete == TODO_NEW) {
				_form.bean = null;
				_form.resetFocus();
				_form.setMessage(new Message("Operation Completed Successfully", Message.TYPE_SUCCESS));
			} else if (todoOnComplete == TODO_CLOSE) {
				hide();
			}
			todoOnComplete = TODO_NOTHING;
		}
		
		private function beanChangedHandler(event:FormEvent):void {
			commitAndNew.visible = event.original == null;
			commitAndNew.includeInLayout = commitAndNew.visible;
		}
		
		private var committingChangeWatcher:ChangeWatcher = ChangeWatcher.watch(null, "committing", committingStateChanged);
		private function committingStateChanged(event:Event=null):void {
			var notCommitting:Boolean = _form != null && !_form.committing;
			var validNotCommitting:Boolean = notCommitting && _form.valid;
			
			commitAndNew.enabled = validNotCommitting;
			commitAndClose.enabled = validNotCommitting;
			commit.enabled = validNotCommitting;
			reset.enabled = notCommitting;
			clear.enabled = notCommitting;
			close.enabled = _form == null || !_form.committing;
		}
		
		
	//PUBLIC INTERFACE
		public function show(bean:*=undefined):void {
			if (bean !== undefined) {
				this.bean = bean;
			}
			PopUpManager.addPopUp(this, displayParent, true);
			PopUpManager.centerPopUp(this);
			_form.resetFocus();
		}
		
		public function hide():void {
			PopUpManager.removePopUp(this);
		}
		
		[Inspectable(enumeration="commitAndClose,commitAndNew,commit,reset,clear,close", defaultValue="commitAndClose")]
		public function set defaultBtn(value:String):void {
			defaultButton = this[value];
		}
		
		[Inspectable(enumeration="commitAndClose,commitAndNew,commit,reset,clear,close", defaultValue="close")]
		public function set cancelBtn(value:String):void {
			cancelButton = this[value];
		}
		
		[Bindable]
		public function set bean(value:*):void {
			if (_form != null)
				_form.bean = value;
		}
		public function get bean():* {
			return _form == null ? null : _form.bean;
		}
		
		[Bindable]
		public function set form(value:FormContainer):void {
			if (_form === value) return;
			if (_form != null) {
				this.removeChild(_form);
				_form.removeEventListener(FormEvent.COMMIT_COMPLETE, commitCompleteHandler);
				_form.removeEventListener(FormEvent.BEAN_CHANGED, beanChangedHandler);
				_form.removeEventListener("validChanged", committingStateChanged);
				committingChangeWatcher.unwatch();
			}
			_form = value;
			if (_form != null) {
				this.addChildAt(_form, 0);
				_form.addEventListener(FormEvent.COMMIT_COMPLETE, commitCompleteHandler);
				_form.addEventListener(FormEvent.BEAN_CHANGED, beanChangedHandler);
				_form.addEventListener("validChanged", committingStateChanged);
				committingChangeWatcher.reset(_form);
			}
			committingStateChanged();
		}
		public function get form():FormContainer {
			return _form;
		}
	
		[Bindable]
		public function set showCommitAndNew(value:Boolean):void {
			commitAndNew.visible = value;
			commitAndNew.includeInLayout = value;
		}
		public function get showCommitAndNew():Boolean {
			return commitAndNew.visible;
		}
		
		[Bindable]
		public function set showCommitAndClose(value:Boolean):void {
			commitAndClose.visible = value;
			commitAndClose.includeInLayout = value;
		}
		public function get showCommitAndClose():Boolean {
			return commitAndClose.visible;
		}
		
		[Bindable]
		public function set showCommit(value:Boolean):void {
			commit.visible = value;
			commit.includeInLayout = value;
		}
		public function get showCommit():Boolean {
			return commit.visible;
		}
		
		[Bindable]
		public function set showReset(value:Boolean):void {
			reset.visible = value;
			reset.includeInLayout = value;
		}
		public function get showReset():Boolean {
			return reset.visible;
		}
		
		[Bindable]
		public function set showClear(value:Boolean):void {
			clear.visible = value;
			clear.includeInLayout = value;
		}
		public function get showClear():Boolean {
			return clear.visible;
		}
		
		[Bindable]
		public function set showClose(value:Boolean):void {
			close.visible = value;
			close.includeInLayout = value;
		}
		public function get showClose():Boolean {
			return close.visible;
		}
		
		[Bindable]
		public function set commitAndNewLabel(value:String):void {
			commitAndNew.label = value;
		}
		public function get commitAndNewLabel():String {
			return commitAndNew.label;
		}
		
		[Bindable]
		public function set commitAndCloseLabel(value:String):void {
			commitAndClose.label = value;
		}
		public function get commitAndCloseLabel():String {
			return commitAndClose.label;
		}
		
		[Bindable]
		public function set commitLabel(value:String):void {
			commit.label = value;
		}
		public function get commitLabel():String {
			return commit.label;
		}
		
		[Bindable]
		public function set resetLabel(value:String):void {
			reset.label = value;
		}
		public function get resetLabel():String {
			return reset.label;
		}
		
		[Bindable]
		public function set clearLabel(value:String):void {
			clear.label = value;
		}
		public function get clearLabel():String {
			return clear.label;
		}
		
		[Bindable]
		public function set closeLabel(value:String):void {
			close.label = value;
		}
		public function get closeLabel():String {
			return close.label;
		}
	}
}